package aor2.cpu.blockinterface;

import aor2.components.ElementIO;
import aor2.components.ElementIOException;
import aor2.components.Restorable;
import aor2.components.Signal;
import aor2.components.Element;

public class Arbitrator implements ElementIO, Restorable {

	private static Arbitrator singleton = null;

	public Signal[] getBrs() {
		return brs;
	}

	public Signal[] getBgs() {
		return bgs;
	}

	// TODO videti da li treba clkphase

	Signal[] brs;
	Signal[] bgs;
	private int state = (int) Element.UNDEFINED;

	public static Arbitrator getInstance() {
		if (null == singleton) {
			singleton = new Arbitrator();
		}
		return singleton;
	}

	public Arbitrator() {
		this.brs = new Signal[4];
		this.bgs = new Signal[4];
		for (int i = 0; i < 4; i++) {
			if (i < 3)
				brs[i] = new Signal(false);
			bgs[i] = new Signal(false);
		}
	}

	public void in() throws ElementIOException {
		int i;
		for (i = 3; i >= 0; i--)
			if (brs[i] == null) {
				throw new ElementIOException();
			}
		for (i = 3; i >= 0; i--)
			if (brs[i].isActive()) {
				state = i;
				break;
			}
		
		if (i < 0)
			state = (int) Element.UNDEFINED;

	}

	public void out() throws ElementIOException {
		for (int i = 3; i >= 0; i--)
			if (bgs[i] == null) {
				throw new ElementIOException();
			}
		for (int i = 3; i >= 0; i--)
			if (!brs[i].isActive()) 
				bgs[i].setActive(false);
		if (state >= 0 && brs[state].isActive())
			bgs[state].setActive(true);
	}

	public void next() {
		/*
		 * if (clkFstPhase) { try { out(); } catch (ElementIOException e){
		 * e.printStackTrace(); } } else { try { in(); } catch
		 * (ElementIOException e){ e.printStackTrace(); } } clkFstPhase =
		 * !clkFstPhase;
		 */
		try {
			in();
			out();
		} catch (ElementIOException e) {
			e.printStackTrace();
		}

	}

	public void restore(String restorePoint) {
		// TODO Auto-generated method stub
		if (singleton == null)
			singleton = new Arbitrator();
		String trim = restorePoint.replace(beginTag(), "");
		trim = trim.replace(endTag(), "");
		trim = trim.trim();
		String[] states = trim.split(" ");
		for (int i = 0; i < 4; i++) {
			brs[i].clearHistory();
			bgs[i].clearHistory();

			brs[i].setActive(Boolean.parseBoolean((states[i])));
			bgs[i].setActive(Boolean.parseBoolean(states[4 + i]));
		}
		state = Integer.parseInt(states[8]);
	}

	public String createRestorePoint() {
		String res = beginTag() + "\n\t" + brs[0].isActive() + " "
				+ brs[1].isActive() + " " + brs[2].isActive() + " ";
		res += brs[3].isActive() + " " + bgs[0].isActive() + " "
				+ bgs[1].isActive() + " " + bgs[2].isActive() + " "
				+ bgs[3].isActive() + " " + state + "\n" + endTag();
		return res;
	}

	public String beginTag() {
		return "<Arbitrator>";
	}

	public String endTag() {
		return "</Arbitrator>";
	}

	public void previousClk() {
		for (int i = 0; i < 3; i++) {
			brs[i].previousClk();
			bgs[i].previousClk();
		}

	}
}
